package com.jcx.ldzj.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.net.UnknownHostException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
     * @Author: yansf
     * @Description:redis配置
     * @Date: 3:18 PM 2018/4/18
     * @Modified By:
     */
@Configuration
@ConditionalOnClass(RedisTemplate.class)
public class RedisConfig {
    //ip地址
    @Value("${spring.redis.host}")
    private String host;
    //跨集群执行命令时要遵循的最大重定向数量
    @Value("${spring.redis.max-redirects}")
    private String redirects;
    //超时时间
    @Value("${spring.redis.timeout}")
    private String timeout;
    //连接密码
    @Value("${spring.redis.password}")
    private String password;


    //最大空闲数，数据库连接的最大空闲时间。超过空闲时间，数据库连
    //接将被标记为不可用，然后被释放。设为0表示无限制。
    @Value("${spring.redis.lettuce.pool.maxIdle}")
    private int maxIdle;

    //连接池中的最小空闲连接数，Druid会定时扫描连接池的连接，如果空闲的连接数大于该值，则关闭多余的连接，反之则创建更多的连接以满足最小连接数要求。
    @Value("${spring.redis.lettuce.pool.minIdle}")
    private int minIdle;
    //最大容量,最大连接数
    @Value("${spring.redis.lettuce.pool.maxTotal}")
    private int maxTotal;

    //请求连接最大等待时间(毫秒)，默认值 无限期 ，超出时间将抛出异常
    @Value("${spring.redis.lettuce.pool.maxWaitMillis}")
    private int maxWaitMillis;


    /**
     * GenericObjectPoolConfig 连接池配置
     */
    @Bean
    public GenericObjectPoolConfig genericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        //最小空闲连接数，默认值 0
        //genericObjectPoolConfig.setMinIdle(0);
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMinIdle(minIdle);
        genericObjectPoolConfig.setMaxTotal(maxTotal);
        genericObjectPoolConfig.setMaxWaitMillis(maxWaitMillis);
        return genericObjectPoolConfig;
    }
    /**
     * 创建连接redis数据以json格式序列化的数据
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        RedisSerializer<?> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);// key序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
        redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }




    /**
     * 创建连接redis存入String的对象
     * @param redisConnectionFactory
     * @return
     * @throws UnknownHostException
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    /**
     * 集群配置方式，将ip端口用逗号隔开后拆分存入配置中
     * @Author: yansf
     * @Description:redis集群配置
     * @Date: 17:45 2020/4/28
     * @Modified By:
     */
    @Bean
    public RedisClusterConfiguration getClusterConfiguration() {
        if (host.split(",").length > 1) {
            //如果是host是集群模式的才进行以下操作
            Map<String, Object> source = new HashMap<String, Object>();
            //单机版本存的直接是host，但集群存的cluster.nodes，但所传参数传入的都是以逗号隔开的主机ip
            source.put("spring.redis.cluster.nodes", host);

            source.put("spring.redis.cluster.timeout", timeout);

            source.put("spring.redis.cluster.max-redirects", redirects);


            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
            redisClusterConfiguration.setPassword(password);
            return redisClusterConfiguration;
        } else {
            return null;
        }

    }

    /**
     * 连接jedis工厂
     * @Author: yansf
     * @Description:集群遍历
     * @Date: 17:50 2020/4/28
     * @Modified By:
     */
    @Bean
    public LettuceConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig genericObjectPoolConfig) {

        // 配置池
        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .commandTimeout(Duration.ofSeconds(Long.parseLong(timeout)))
                .poolConfig(genericObjectPoolConfig)
                .build();
        //单机配置
        if (host.split(",").length == 1) {
            RedisStandaloneConfiguration redisStandaloneConfiguration = 
                    new RedisStandaloneConfiguration(
                            host.split(":")[0]
                            ,Integer.valueOf(host.split(":")[1]));
            redisStandaloneConfiguration.setPassword(password);
            LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration,clientConfig);
            return factory;
        } else {
            LettuceConnectionFactory jcf = new LettuceConnectionFactory(getClusterConfiguration(),clientConfig);
            return jcf;
        }
    }

//    private String master;
//    private List<String> nodes;
//    private String password;
//    private String timeout;
//
//    /**
//     * 哨兵配置,目前么有用到，目前用的都是单机或者集群
//     **/
//    @Bean
//    public LettuceConnectionFactory redisConnectionFactory(GenericObjectPoolConfig genericObjectPoolConfig) {
//        /
//        RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(master,
//                new HashSet<String>(nodes));
//        redisSentinelConfiguration.setPassword(password);
//        // 配置池
//        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
//                .commandTimeout(timeout)
//                .poolConfig(genericObjectPoolConfig)
//                .build();
//        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration,clientConfig);
//        log.debug("redis 哨兵启动");
//        return lettuceConnectionFactory;
//    }
}